package com.fingard.dsp.bank.directbank.cmb02.util;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 这是CDes的帮助类，
 * 
 * @author HO074337
 * 
 */
public class CDesHelper {

	private final static Log log = LogFactory.getLog(CDesHelper.class);

	private CDesHelper() {

	}

	/**
	 * 加密
	 * 
	 * @param pPlaintText
	 *                明文16位的16进制
	 * @param pKey
	 *                密文16位的16进制
	 * @return 返回密文 16的16进制数据
	 * @throws EncryptException
	 */
	public static String encrypt(String pPlaintText, String pKey) throws EncryptException {
		if (pPlaintText == null || pKey == null) {
			return null;
		}
		/**
		 * @todo: 实际上只要是16倍数就可以
		 */
		if (pPlaintText.length() != 16) {
			throw new EncryptException("明文长度不是16位.明文必须是长度为16位的16进制数据.如：74657374656E6372!");
		}
		if (pKey.length() != 16) {
			throw new EncryptException("密钥长度不是16位.密钥必须是长度为16位的16进制数据.如：74657374656E6372!");
		}
		/**
		 * 注意：java的16进制数据字母是用a,b,c,d,e,f表示，而c是用大写字母A,B,C,D,E,F表示，
		 * 所以这里要注意大小写转换处理
		 */
		char[] plainChars = getCharArray(pPlaintText.toLowerCase());
		char[] keyChars = getCharArray(pKey.toLowerCase());
		byte[] plainBytes = null;
		byte[] keyBytes = null;
		try {
			plainBytes = Hex.decodeHex(plainChars);
		} catch (DecoderException e) {
			e.printStackTrace();
			final String MSG = "将明文:'" + pPlaintText + "'解码为16进制数据出错!" + e.getMessage();
			log.error(MSG, e);
			throw new EncryptException(MSG, e);
		}

		try {
			keyBytes = Hex.decodeHex(keyChars);
		} catch (DecoderException e) {
			e.printStackTrace();
			final String MSG = "将密钥:'" + pKey + "'解码为16进制数据出错!" + e.getMessage();
			log.error(MSG, e);
			throw new EncryptException(MSG, e);
		}
		CDesCipher des = new CDesCipher(keyBytes);
		byte[] result = new byte[plainBytes.length];
		des.encrypt(plainBytes, result);
		return new String(Hex.encodeHex(result)).toUpperCase();
	}

	private static char[] getCharArray(String pStr) {
		if (pStr == null) {
			return null;
		}
		char[] result = new char[pStr.length()];
		for (int i = 0; i < result.length; i++) {
			result[i] = pStr.charAt(i);
		}
		return result;
	}

	public static String encodeHex(String pStr) {
		if (pStr == null) {
			return null;
		}
		byte[] result = new byte[pStr.length()];
		for (int i = 0; i < result.length; i++) {
			result[i] = (byte) pStr.charAt(i);
		}
		String a = new String(Hex.encodeHex(result)).toUpperCase();// 变成大写字母
		return a;
	}

	/**
	 * 解密
	 * 
	 * @param encryptText
	 *                密文16位的16进制
	 * @param pKey
	 *                密文16位的16进制
	 * @return 返回明文 16的16进制数据
	 * @throws DecryptException
	 */
	public static String decrypt(String encryptText, String pKey) throws DecryptException {
		if (encryptText == null || pKey == null) {
			return null;
		}
		/**
		 * @todo: 实际上只要是16倍数就可以
		 */
		if (encryptText.length() != 16) {
			throw new EncryptException("密文长度不是16位.密文必须是长度为16位的16进制数据.如：74657374656E6372!");
		}
		if (pKey.length() != 16) {
			throw new EncryptException("密钥长度不是16位.密钥必须是长度为16位的16进制数据.如：74657374656E6372!");
		}
		/**
		 * 注意：java的16进制数据字母是用a,b,c,d,e,f表示，而c是用大写字母A,B,C,D,E,F表示，
		 * 所以这里要注意大小写转换处理
		 */

		char[] encryptChars = getCharArray(encryptText.toLowerCase());
		char[] keyChars = getCharArray(pKey.toLowerCase());
		byte[] encryptBytes = null;
		byte[] keyBytes = null;
		try {
			encryptBytes = Hex.decodeHex(encryptChars);
		} catch (DecoderException e) {
			e.printStackTrace();
			final String MSG = "将密文:'" + encryptText + "'解码为16进制数据出错!" + e.getMessage();
			log.error(MSG, e);
			throw new EncryptException(MSG, e);
		}

		try {
			keyBytes = Hex.decodeHex(keyChars);
		} catch (DecoderException e) {
			e.printStackTrace();
			final String MSG = "将密钥:'" + pKey + "'解码为16进制数据出错!" + e.getMessage();
			log.error(MSG, e);
			throw new EncryptException(MSG, e);
		}
		CDesCipher des = new CDesCipher(keyBytes);
		byte[] result = new byte[encryptBytes.length];
		des.decrypt(encryptBytes, result);
		return new String(Hex.encodeHex(result)).toUpperCase();
	}
}
